home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / ftpserv.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  20KB  |  870 lines

  1. /* Internet FTP Server server machine - see RFC 959
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <time.h>
  7. #ifdef  __TURBOC__
  8. #include <io.h>
  9. #include <dir.h>
  10. #endif
  11. #ifdef UNIX
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #endif
  15. #include "global.h"
  16. #include "mbuf.h"
  17. #include "socket.h"
  18. #include "ftp.h"
  19. #include "ftpserv.h"
  20. #include "proc.h"
  21. #include "dirutil.h"
  22. #include "files.h"
  23. #include "commands.h"
  24. #include "config.h"
  25. #include "cmdparse.h"
  26.  
  27. static void ftpserv __ARGS((int s,void *unused,void *p));
  28. static int pport __ARGS((struct sockaddr_in *sock,char *arg));
  29. static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  30. static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
  31. static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  32. int doftptdisc __ARGS((int argc, char *argv[], void *p));
  33.  
  34. #ifdef __cplusplus
  35. extern "C" {
  36. #endif
  37. extern int access __ARGS((const char *,int));
  38. extern int unlink __ARGS((const char *));
  39. extern int rmdir __ARGS((const char *));
  40. #ifdef __cplusplus
  41. }
  42. #endif
  43.  
  44. #ifdef UNIX
  45. extern unsigned long filelength __ARGS((int));
  46. #endif
  47.  
  48. /* Command table */
  49. static char *commands[] = {
  50.     "user",
  51.     "acct",
  52.     "pass",
  53.     "type",
  54.     "list",
  55.     "cwd",
  56.     "dele",
  57.     "name",
  58.     "quit",
  59.     "retr",
  60.     "stor",
  61.     "port",
  62.     "nlst",
  63.     "pwd",
  64.     "xpwd",                 /* For compatibility with 4.2BSD */
  65.     "mkd ",
  66.     "xmkd",                 /* For compatibility with 4.2BSD */
  67.     "xrmd",                 /* For compatibility with 4.2BSD */
  68.     "rmd ",
  69.     "stru",
  70.     "mode",
  71.     "rsme",                 /* Added by IW0CNB, for resuming interrupted trasnfers */
  72.     "rput",
  73.     "syst",            /* 1.10 and Unix use this */
  74.     NULLCHAR
  75. };
  76.  
  77. /* Response messages */
  78. static char banner[] = "220- %s, KA9Q-NOS FTP version %s\n";
  79. static char banner1[] = "220  Ready on %s";
  80. static char badcmd[] = "500 Unknown command\n";
  81. static char binwarn[] = "100 Warning: type is ASCII and %s appears to be binary\n";
  82. static char unsupp[] = "500 Unsupported command or option\n";
  83. static char givepass[] = "331 Enter PASS command\n";
  84. /* static char challenge[] = "399 PASS challenge : %016lx\r\n"; */
  85. static char logged[] = "230 Logged in\n";
  86. static char loggeda[] = "230 Logged in as anonymous, restrictions apply\n";
  87. static char typeok[] = "200 Type %s OK\n";
  88. static char only8[] = "501 Only logical bytesize 8 supported\n";
  89. static char deleok[] = "250 File deleted\n";
  90. static char mkdok[] = "200 MKD ok\n";
  91. static char delefail[] = "550 Delete failed: %s\n";
  92. static char pwdmsg[] = "257 \"%s\" is current directory\n";
  93. static char badtype[] = "501 Unknown type \"%s\"\n";
  94. static char badport[] = "501 Bad port syntax\n";
  95. static char unimp[] = "502 Command not yet implemented\n";
  96. static char bye[] = "221 Goodbye!\n";
  97. static char nodir[] = "553 Can't read directory \"%s\": %s\n";
  98. static char cantopen[] = "550 Can't read file \"%s\": %s\n";
  99. static char sending[] = "150 Opening data connection for %s %s %s\n"; /*N1BEE*/
  100. static char cantmake[] = "553 Can't create \"%s\": %s\n";
  101. static char writerr[] = "552 Write error: %s\n";
  102. static char portok[] = "200 Port command okay\n";
  103. static char rxok[] = "226 File received OK\n";
  104. static char txok[] = "226 File sent OK\n";
  105. static char noperm[] = "550 Permission denied\n";
  106. static char noconn[] = "425 Data connection reset\n";
  107. static char badcheck[] = "425 Bad checksum\n";
  108. static char lowmem[] = "421 System overloaded, try again later\n";
  109. static char notlog[] = "530 Please log in with USER and PASS\n";
  110. static char userfirst[] = "503 Login with USER first.\n";
  111. static char okay[] = "200 Ok\n";
  112. static char systresp[] = "215 UNIX Type: L8 Version: %s\n";
  113.  
  114. static int Sftp = -1;   /* Prototype socket for service */
  115.  
  116. #ifdef FTPTDISC
  117. int32 Ftptdiscinit = 0;
  118.  
  119. /* Set ftp redundancy timer */
  120. int
  121. doftptdisc(argc,argv,p)
  122. int argc;
  123. char *argv[];
  124. void *p;
  125. {
  126.     return setlong(&Ftptdiscinit,"Ftp redundancy timer (sec)",argc,argv);
  127. }
  128.  
  129. static void
  130. #ifdef PROTOTYPES
  131. ftp_redundant(struct ftpserv *ftp)
  132. #else
  133. ftp_redundant(ftp)
  134. struct ftpserv *ftp;
  135. #endif
  136. {
  137.     /* Clean up */
  138.     shutdown(ftp->control,2);
  139.     close_s(ftp->control);
  140.     if(ftp->data != -1){
  141.     shutdown(ftp->data,2);
  142.     close_s(ftp->data);
  143.     ftp->data = -1;
  144.     }
  145.     return;
  146. }
  147. #endif
  148.  
  149. /* Start up FTP service */
  150. int
  151. ftpstart(argc,argv,p)
  152. int argc;
  153. char *argv[];
  154. void *p;
  155. {
  156.     struct sockaddr_in lsocket;
  157.     int s;
  158.  
  159.     if(Sftp != -1){
  160.         /* Already running! */
  161.         return 0;
  162.     }
  163.     psignal(Curproc,0);     /* Don't keep the parser waiting */
  164.     chname(Curproc,"FTP listener");
  165.  
  166.     lsocket.sin_family = AF_INET;
  167.     lsocket.sin_addr.s_addr = INADDR_ANY;
  168.     if(argc < 2)
  169.         lsocket.sin_port = IPPORT_FTP;
  170.     else
  171.         lsocket.sin_port = atoi(argv[1]);
  172.  
  173.     Sftp = socket(AF_INET,SOCK_STREAM,0);
  174.     bind(Sftp,(char *)&lsocket,sizeof(lsocket));
  175.     listen(Sftp,1);
  176.     for(;;){
  177.         if((s = accept(Sftp,NULLCHAR,(int *)NULL)) == -1)
  178.             break;  /* Service is shutting down */
  179.  
  180. #ifndef UNIX
  181.         if(availmem() < Memthresh){
  182.             usprintf(s,lowmem);
  183.             shutdown(s,1);
  184.         } else {
  185. #endif
  186.             /* Spawn a server */
  187.             newproc("ftpserv",2048,ftpserv,s,NULL,NULL,0);
  188. #ifndef UNIX
  189.         }
  190. #endif
  191.     }
  192.     return 0;
  193. }
  194. static void
  195. ftpserv(s,unused,p)
  196. int s;  /* Socket with user connection */
  197. void *unused;
  198. void *p;
  199. {
  200.     struct ftpserv ftp;
  201.     char **cmdp,buf[512],*arg,*cp,*file,*mode;
  202. #ifdef notdef
  203.     char *cp1;
  204. #endif
  205.     long t;
  206.     int cnt,i;
  207.     struct sockaddr_in socket;
  208.     FILE *fp;
  209.     extern char shortversion[];
  210.  
  211.     sockmode(s,SOCK_ASCII);
  212.     memset((char *)&ftp,0,sizeof(ftp));     /* Start with clear slate */
  213.     ftp.data = -1;
  214.  
  215.     sockowner(s,Curproc);           /* We own it now */
  216.     ftp.control = s;
  217.     /* Set default data port */
  218.     i = SOCKSIZE;
  219.     getpeername(s,(char *)&socket,&i);
  220.     socket.sin_port = IPPORT_FTPD;
  221.     ASSIGN(ftp.port,socket);
  222.  
  223. #ifdef FTPTDISC
  224.     /* Set the timeout timer - WG7J */
  225.     set_timer(&ftp.tdisc,Ftptdiscinit * 1000L);
  226.     ftp.tdisc.func = (void(*)__FARGS((void*)))ftp_redundant;
  227.     ftp.tdisc.arg = &ftp;
  228.     start_timer(&ftp.tdisc);
  229. #endif
  230.  
  231.     log(s,"open FTP");
  232.     usprintf(s,banner,Hostname,Version);
  233.     if((fp = fopen(Ftpmotd,"r")) != NULL) {
  234.     while(fgets(buf,128,fp)) {
  235.         rip(buf);
  236.         usprintf(s,"220- %s\n",buf);
  237.     }
  238.     fclose(fp);
  239.     }
  240.     time(&t);
  241.     cp = ctime(&t);
  242.     
  243. #ifdef notdef
  244.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  245.     *cp1 = '\0';
  246. #endif
  247.     
  248.     usprintf(s,banner1,cp);
  249.  
  250. loop:   if((cnt = recvline(s,buf,sizeof(buf))) == -1){
  251.         /* He closed on us */
  252.         goto finish;
  253.     }
  254.  
  255. #ifdef FTPTDISC
  256.     /* Reset the timeout timer - WG7J */
  257.     start_timer(&ftp.tdisc);
  258. #endif
  259.     
  260.     if(cnt == 0){
  261.         /* Can't be a legal FTP command */
  262.         usprintf(ftp.control,badcmd);
  263.         goto loop;
  264.     }
  265.     rip(buf);
  266.     /* Translate first word to lower case */
  267.     for(cp = buf;*cp != ' ' && *cp != '\0';cp++)
  268.         *cp = tolower(*cp);
  269.     /* Find command in table; if not present, return syntax error */
  270.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  271.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  272.             break;
  273.     if(*cmdp == NULLCHAR){
  274.         usprintf(ftp.control,badcmd);
  275.         goto loop;
  276.     }
  277.     /* Allow only USER, PASS and QUIT before logging in */
  278.     if(ftp.cd == NULLCHAR || ftp.path == NULLCHAR){
  279.         switch(cmdp-commands){
  280.         case USER_CMD:
  281.         case PASS_CMD:
  282.         case QUIT_CMD:
  283.             break;
  284.         default:
  285.             usprintf(ftp.control,notlog);
  286.             goto loop;
  287.         }
  288.     }
  289.     arg = &buf[strlen(*cmdp)];
  290.     while(*arg == ' ')
  291.         arg++;
  292.  
  293.     /* Execute specific command */
  294.     switch(cmdp-commands){
  295.     case USER_CMD:
  296.         free(ftp.username);
  297.         ftp.username = strdup(arg);
  298.          /*   if(sp_user(ftp.username)) {
  299.             time(&ftp.ttim);
  300.             usprintf(ftp.control,challenge,ftp.ttim);
  301.         }
  302.         else
  303.          */           
  304.             usprintf(ftp.control,givepass);
  305.         break;
  306.     case TYPE_CMD:
  307.         switch(arg[0]){
  308.         case 'A':
  309.         case 'a':       /* Ascii */
  310.             ftp.type = ASCII_TYPE;
  311.             usprintf(ftp.control,typeok,arg);
  312.             break;
  313.         case 'l':
  314.         case 'L':
  315.             while(*arg != ' ' && *arg != '\0')
  316.                 arg++;
  317.             if(*arg == '\0' || *++arg != '8'){
  318.                 usprintf(ftp.control,only8);
  319.                 break;
  320.             }
  321.             ftp.type = LOGICAL_TYPE;
  322.             ftp.logbsize = 8;
  323.             usprintf(ftp.control,typeok,arg);
  324.             break;
  325.         case 'B':
  326.         case 'b':       /* Binary */
  327.         case 'I':
  328.         case 'i':       /* Image */
  329.             ftp.type = IMAGE_TYPE;
  330.             usprintf(ftp.control,typeok,arg);
  331.             break;
  332.         default:        /* Invalid */
  333.             usprintf(ftp.control,badtype,arg);
  334.             break;
  335.         }
  336.         break;
  337.     case QUIT_CMD:
  338.         usprintf(ftp.control,bye);
  339.         goto finish;
  340.     case RETR_CMD:
  341.     case RSME_CMD:
  342.         file = pathname(ftp.cd,arg);
  343.         switch(ftp.type){
  344.         case IMAGE_TYPE:
  345.         case LOGICAL_TYPE:
  346.             mode = READ_BINARY;
  347.             break;
  348. #ifdef __GNUC__
  349.         default:
  350. #endif
  351.         case ASCII_TYPE:
  352.             mode = READ_TEXT;
  353.             break;
  354.         }
  355.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  356.             usprintf(ftp.control,noperm);
  357.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  358.             usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  359.         } else {
  360.             if((cmdp-commands) == RSME_CMD) {
  361.                 log(ftp.control,"RSME %s",file);
  362.                 if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  363.                     usprintf(ftp.control,binwarn,file);
  364.                 }
  365.                 sendit(&ftp,"RSME",file);
  366.             } else {
  367.                 log(ftp.control,"RETR %s",file);
  368.                 if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  369.                     usprintf(ftp.control,binwarn,file);
  370.                 }
  371.                 sendit(&ftp,"RETR",file);
  372.             }
  373.         }
  374.         free(file);
  375.         break;
  376.     case STOR_CMD:
  377.     case RPUT_CMD:
  378.         file = pathname(ftp.cd,arg);
  379.         switch(ftp.type){
  380.         case IMAGE_TYPE:
  381.         case LOGICAL_TYPE:
  382.             if(cmdp-commands == RPUT_CMD)
  383.                 mode = APPEND_BINARY;
  384.             else
  385.                 mode = WRITE_BINARY;
  386.             break;
  387. #ifdef __GNUC__
  388.         default:
  389. #endif
  390.         case ASCII_TYPE:
  391.             if(cmdp-commands == RPUT_CMD)
  392.                 mode = APPEND_TEXT;
  393.             else
  394.                 mode = WRITE_TEXT;
  395.             break;
  396.         }
  397.         if(cmdp-commands == RPUT_CMD){
  398.             if(!permcheck(ftp.path,ftp.perms,RPUT_CMD,file)){
  399.                 usprintf(ftp.control,noperm);
  400.             } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  401.                 usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  402.             } else {
  403.                 log(ftp.control,"RPUT %s",file);
  404.                 recvit(&ftp,"RPUT",file);
  405.             }
  406.         } else {
  407.             if(!permcheck(ftp.path,ftp.perms,STOR_CMD,file)){
  408.                 usprintf(ftp.control,noperm);
  409.             } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  410.                 usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  411.             } else {
  412.                 log(ftp.control,"STOR %s",file);
  413.                 recvit(&ftp,"STOR",file);
  414.             }
  415.         }
  416.         free(file);
  417.         break;
  418.     case PORT_CMD:
  419.         if(pport(&ftp.port,arg) == -1){
  420.             usprintf(ftp.control,badport);
  421.         } else {
  422.             usprintf(ftp.control,portok);
  423.         }
  424.         break;
  425. #ifndef CPM
  426.     case LIST_CMD:
  427.         /* ignore arguments starting with '-' */
  428.         while (*arg == '-')
  429.         {
  430.             while (*++arg && *arg != ' ')
  431.             ;
  432.             while (*arg && *arg != ' ')
  433.             arg++;
  434.         }
  435.         file = pathname(ftp.cd,arg);
  436.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  437.             usprintf(ftp.control,noperm);
  438.         } else if((ftp.fp = dir(file,1)) == NULLFILE){
  439.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  440.         } else {
  441.             sendit(&ftp,"LIST",file);
  442.         }
  443.         free(file);
  444.         break;
  445.     case NLST_CMD:
  446.         /* ignore arguments starting with '-' */
  447.         while (*arg == '-')
  448.         {
  449.             while (*++arg && *arg != ' ')
  450.             ;
  451.             while (*arg && *arg != ' ')
  452.             arg++;
  453.         }
  454.         file = pathname(ftp.cd,arg);
  455.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  456.             usprintf(ftp.control,noperm);
  457.         } else if((ftp.fp = dir(file,0)) == NULLFILE){
  458.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  459.         } else {
  460.             sendit(&ftp,"NLST",file);
  461.         }
  462.         free(file);
  463.         break;
  464.     case CWD_CMD:
  465.         file = pathname(ftp.cd,arg);
  466.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  467.             usprintf(ftp.control,noperm);
  468.             free(file);
  469. #ifdef  MSDOS
  470.         /* Don'tcha just LOVE %%$#@!! MS-DOS? */
  471.         } else if(strcmp(file,"/") == 0 || access(file,0) == 0){
  472. #else
  473.         } else if(access(file,0) == 0){ /* See if it exists */
  474. #endif
  475.             /* Succeeded, record in control block */
  476.             free(ftp.cd);
  477.             ftp.cd = file;
  478.             usprintf(ftp.control,pwdmsg,file);
  479.         } else {
  480.             /* Failed, don't change anything */
  481.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  482.             free(file);
  483.         }
  484.         break;
  485.     case XPWD_CMD:
  486.     case PWD_CMD:
  487.         usprintf(ftp.control,pwdmsg,ftp.cd);
  488.         break;
  489. #else
  490.     case LIST_CMD:
  491.     case NLST_CMD:
  492.     case CWD_CMD:
  493.     case XPWD_CMD:
  494.     case PWD_CMD:
  495. #endif
  496.     case ACCT_CMD:
  497.         usprintf(ftp.control,unimp);
  498.         break;
  499.     case DELE_CMD:
  500.         file = pathname(ftp.cd,arg);
  501.         if(!permcheck(ftp.path,ftp.perms,DELE_CMD,file)){
  502.             usprintf(ftp.control,noperm);
  503.         } else if(unlink(file) == 0){
  504.             log(ftp.control,"DELE %s",file);
  505.             usprintf(ftp.control,deleok);
  506.         } else {
  507.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  508.         }
  509.         free(file);
  510.         break;
  511.     case PASS_CMD:
  512.         if(ftp.username == NULLCHAR)
  513.             usprintf(ftp.control,userfirst);
  514.         else
  515.             ftplogin(&ftp,arg);
  516.         break;
  517. #ifndef CPM
  518.     case XMKD_CMD:
  519.     case MKD_CMD:
  520.         file = pathname(ftp.cd,arg);
  521.         if(!permcheck(ftp.path,ftp.perms,MKD_CMD,file)){
  522.             usprintf(ftp.control,noperm);
  523. #ifdef  UNIX
  524.         } else if(mkdir(file,0777) == 0){
  525. #else
  526.         } else if(mkdir(file) == 0){
  527. #endif
  528.             log(ftp.control,"MKD %s",file);
  529.             usprintf(ftp.control,mkdok);
  530.         } else {
  531.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  532.         }
  533.         free(file);
  534.         break;
  535.     case XRMD_CMD:
  536.     case RMD_CMD:
  537.         file = pathname(ftp.cd,arg);
  538.         if(!permcheck(ftp.path,ftp.perms,RMD_CMD,file)){
  539.             usprintf(ftp.control,noperm);
  540.         } else if(rmdir(file) == 0){
  541.             log(ftp.control,"RMD %s",file);
  542.             usprintf(ftp.control,deleok);
  543.         } else {
  544.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  545.         }
  546.         free(file);
  547.         break;
  548.     case STRU_CMD:
  549.         if(tolower(arg[0]) != 'f')
  550.             usprintf(ftp.control,unsupp);
  551.         else
  552.             usprintf(ftp.control,okay);
  553.         break;
  554.     case MODE_CMD:
  555.         if(tolower(arg[0]) != 's')
  556.             usprintf(ftp.control,unsupp);
  557.         else
  558.             usprintf(ftp.control,okay);
  559.         break;
  560.     case SYST_CMD:
  561.         usprintf(ftp.control, systresp, shortversion);
  562.         break;
  563.     }
  564. #endif
  565.     goto loop;
  566. finish:
  567.     
  568. #ifdef FTPTDISC
  569.     stop_timer(&ftp.tdisc);
  570. #endif
  571.     
  572.     log(ftp.control,"close FTP");
  573.     /* Clean up */
  574.     close_s(ftp.control);
  575.     if(ftp.data != -1)
  576.         close_s(ftp.data);
  577.     if(ftp.fp != NULLFILE)
  578.         fclose(ftp.fp);
  579.     free(ftp.username);
  580.     free(ftp.path);
  581.     free(ftp.cd);
  582. }
  583.  
  584. /* Shut down FTP server */
  585. int
  586. ftp0(argc,argv,p)
  587. int argc;
  588. char *argv[];
  589. void *p;
  590. {
  591.     close_s(Sftp);
  592.     Sftp = -1;
  593.     return 0;
  594. }
  595. static
  596. int
  597. pport(sock,arg)
  598. struct sockaddr_in *sock;
  599. char *arg;
  600. {
  601.     int32 n;
  602.     int i;
  603.  
  604.     n = 0;
  605.     for(i=0;i<4;i++){
  606.         n = atoi(arg) + (n << 8);
  607.         if((arg = strchr(arg,',')) == NULLCHAR)
  608.             return -1;
  609.         arg++;
  610.     }
  611.     sock->sin_addr.s_addr = n;
  612.     n = atoi(arg);
  613.     if((arg = strchr(arg,',')) == NULLCHAR)
  614.         return -1;
  615.     arg++;
  616.     n = atoi(arg) + (n << 8);
  617.     sock->sin_port = n;
  618.     return 0;
  619. }
  620.  
  621. /* Attempt to log in the user whose name is in ftp->username and password
  622.  * in pass
  623.  */
  624. static void
  625. ftplogin(ftp,pass)
  626. struct ftpserv *ftp;
  627. char *pass;
  628. {
  629.     char *path;
  630.     char *p;
  631.     int anony = 0;
  632.  
  633.     path = mallocw(200);
  634.     if((ftp->perms = userlogin(ftp->username,pass,&path,200,&anony))
  635.        == -1){
  636.         usprintf(ftp->control,noperm);
  637.         free(path);
  638.         return;
  639.     }
  640.     /* Set up current directory and path prefix */
  641. #if     defined(AMIGAGONE)
  642.     ftp->cd = pathname("", path);
  643.     ftp->path = strdup(ftp->cd);
  644.     free(path);
  645. #else
  646.     ftp->cd = path;
  647.     ftp->path = strdup(path);
  648.     if((p = strchr(path,';')) != '\0')
  649.         *p = '\0';              /* delimit initial cd */
  650. #endif
  651.  
  652.     if(!anony){
  653.         usprintf(ftp->control,logged);
  654.         log(ftp->control,"%s logged in",ftp->username);
  655.     } else {
  656.         usprintf(ftp->control,loggeda);
  657.         log(ftp->control,"%s logged in, ID %s",ftp->username,pass);
  658.     }
  659. }
  660.  
  661. #ifdef  MSDOS
  662. /* Illegal characters in a DOS filename */
  663. static char badchars[] = "\"[]:|<>+=;,";
  664. #endif
  665.  
  666. /* Return 1 if the file operation is allowed, 0 otherwise */
  667. int
  668. permcheck(path,perms,op,file)
  669. char *path;
  670. int perms;
  671. int op;
  672. char *file;
  673. {
  674.     char *cp, *cp1;
  675.  
  676.     if(file == NULLCHAR || path == NULLCHAR)
  677.         return 0;       /* Probably hasn't logged in yet */
  678. #ifndef MAC
  679.     /* The target file must be under the user's allowed search path */
  680.     /* We let them specify multiple paths using path;path... -russ */
  681.     for(cp = path;;cp =cp1+1){
  682.         if((cp1=strchr(cp,';')) == NULLCHAR) cp1=strchr(cp,'\0');
  683.         if((strncmp(file,cp,(size_t)(cp1 - cp))) == 0) break;
  684.         if(*cp1 == '\0') return 0;
  685.     }
  686. #endif
  687. #ifdef  MSDOS
  688.     /* Check for characters illegal in MS-DOS file names */
  689.     for(cp = badchars;*cp != '\0';cp++){
  690.         if(strchr(file,*cp) != NULLCHAR)
  691.             return 0;
  692.     }
  693. #endif
  694.  
  695.     switch(op){
  696.     case RETR_CMD:
  697.         /* User must have permission to read files */
  698.         if(perms & FTP_READ)
  699.             return 1;
  700.         return 0;
  701.     case DELE_CMD:
  702.     case RMD_CMD:
  703.     case RPUT_CMD:
  704.         /* User must have permission to (over)write files */
  705.         if(perms & FTP_WRITE)
  706.             return 1;
  707.         return 0;
  708.     case STOR_CMD:
  709.     case MKD_CMD:
  710.         /* User must have permission to (over)write files, or permission
  711.          * to create them if the file doesn't already exist
  712.          */
  713.         if(perms & FTP_WRITE)
  714.             return 1;
  715.         if(access(file,2) == -1 && (perms & FTP_CREATE))
  716.             return 1;
  717.         return 0;
  718.     }
  719.     return 0;       /* "can't happen" -- keep lint happy */
  720. }
  721. static int
  722. sendit(ftp,command,file)
  723. struct ftpserv *ftp;
  724. char *command;
  725. char *file;
  726. {
  727.     long total, starting;
  728.     unsigned long check;
  729.     struct sockaddr_in dport;
  730.     char *cp;
  731.     char fsizetext[20] = "";                /* N1BEE */
  732.  
  733.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  734.     dport.sin_family = AF_INET;
  735.     dport.sin_addr.s_addr = INADDR_ANY;
  736.     dport.sin_port = IPPORT_FTPD;
  737.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  738.     sprintf(fsizetext, "(%lu bytes)", filelength(fileno(ftp->fp)));
  739.     usprintf(ftp->control,sending,command,file,fsizetext);  /* N1BEE */
  740.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  741.         fclose(ftp->fp);
  742.         ftp->fp = NULLFILE;
  743.         close_s(ftp->data);
  744.         ftp->data = -1;
  745.         usprintf(ftp->control,noconn);
  746.         return -1;
  747.     }
  748.     if(strcmp(command,"RSME") == 0) {
  749. #ifdef __GNUC__
  750.         total = -1;
  751. #endif
  752.         cp = mallocw(40);
  753.         recvline(ftp->control,cp,40);
  754.         starting = atol(cp);
  755.         /* If checksum field is not present go on anyway, for compatibility
  756.          * with previous scheme. If present check it and barf if wrong.
  757.          */
  758.         if(strchr(cp,' ') != NULL){
  759.             check = (unsigned long)atol(strchr(cp,' '));
  760.             check -= checksum(ftp->fp,starting);
  761.             if(check != 0){
  762.                 free(cp);
  763.                 usprintf(ftp->control,badcheck);
  764.                 shutdown(ftp->data,1);  /* Blow away data connection */
  765.                 goto send_err;
  766.             }
  767.         } else if(fseek(ftp->fp,starting,SEEK_SET) != 0) {
  768.             free(cp);
  769.             usprintf(ftp->control,noconn);
  770.             shutdown(ftp->data,2);  /* Blow away data connection */
  771.             goto send_err;
  772.         }
  773.     }
  774.  
  775. #ifdef FTPTDISC
  776.     /* Turn off the timeout timer here, some ftp's could
  777.      * take a long time with sloooow packet channels - WG7J
  778.      */
  779.     stop_timer(&ftp->tdisc);
  780. #endif
  781.     
  782.     /* Do the actual transfer */
  783.     total = sendfile(ftp->fp,ftp->data,ftp->type,0);
  784.  
  785. #ifdef FTPTDISC
  786.     /* And turn it back on now */
  787.     start_timer(&ftp->tdisc);
  788. #endif
  789.  
  790.     if(total == -1){
  791.         /* An error occurred on the data connection */
  792.         usprintf(ftp->control,noconn);
  793.         shutdown(ftp->data,2);  /* Blow away data connection */
  794.     } else {
  795.         usprintf(ftp->control,txok);
  796.     }
  797. send_err:       fclose(ftp->fp);
  798.     ftp->fp = NULLFILE;
  799.     close_s(ftp->data);
  800.     ftp->data = -1;
  801.     if(total == -1)
  802.         return -1;
  803.     else
  804.         return 0;
  805. }
  806. static int
  807. recvit(ftp,command,file)
  808. struct ftpserv *ftp;
  809. char *command;
  810. char *file;
  811. {
  812.     struct sockaddr_in dport;
  813.     long total, starting;
  814.  
  815.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  816.     dport.sin_family = AF_INET;
  817.     dport.sin_addr.s_addr = INADDR_ANY;
  818.     dport.sin_port = IPPORT_FTPD;
  819.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  820.     usprintf(ftp->control,sending,command,file,"");
  821.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  822.         fclose(ftp->fp);
  823.         ftp->fp = NULLFILE;
  824.         close_s(ftp->data);
  825.         ftp->data = -1;
  826.         usprintf(ftp->control,noconn);
  827.         return -1;
  828.     }
  829.     if(strcmp(command,"RPUT") == 0){
  830.         if((starting = getsize(ftp->fp)) == -1)
  831.             starting = 0L;
  832.         usprintf(ftp->control,"%ld %lu\n",starting,checksum(ftp->fp,starting));
  833.         fseek(ftp->fp,starting,SEEK_SET);
  834.     }
  835.  
  836. #ifdef FTPTDISC
  837.     /* Turn off the timeout timer here; some ftp's could
  838.      * take a long time with sloooow packet channels - WG7J
  839.      */
  840.     stop_timer(&ftp->tdisc);
  841. #endif
  842.     
  843.     total = recvfile(ftp->fp,ftp->data,ftp->type,0);
  844.  
  845. #ifdef FTPTDISC
  846.     /* And turn it back on now */
  847.     start_timer(&ftp->tdisc);
  848. #endif
  849.  
  850. #ifdef  CPM
  851.     if(ftp->type == ASCII_TYPE)
  852.         putc(CTLZ,ftp->fp);
  853. #endif
  854.     if(total == -1) {
  855.         /* An error occurred while writing the file */
  856.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  857.         shutdown(ftp->data,2);  /* Blow it away */
  858.     } else {
  859.         usprintf(ftp->control,rxok);
  860.     }
  861.     close_s(ftp->data);
  862.     ftp->data = -1;
  863.     fclose(ftp->fp);
  864.     ftp->fp = NULLFILE;
  865.     if(total == -1)
  866.         return -1;
  867.     else
  868.         return 0;
  869. }
  870.